"use client";

import * as React from "react";

import { refreshTokens } from "@/lib/api-client";
import { COOKIE_ACCESS_TOKEN, COOKIE_REFRESH_TOKEN } from "@/lib/constants";

export type AuthTokens = {
  accessToken: string;
  refreshToken: string;
};

export type UserSummary = {
  id: string;
  email: string;
  displayName: string;
  roles: string[];
  phone?: string | null;
};

export type PersistedAuthState = {
  tokens: AuthTokens;
  user: UserSummary | null;
};

export type AuthContextValue = {
  user: UserSummary | null;
  tokens: AuthTokens | null;
  isAuthenticated: boolean;
  isLoading: boolean;
  signIn: (payload: PersistedAuthState) => void;
  signOut: () => void;
  updateUser: (user: UserSummary | null) => void;
  refresh: () => Promise<AuthTokens | null>;
};

const STORAGE_KEY = "bo.auth";
const COOKIE_MAX_AGE = 60 * 60 * 24 * 7; // 7 days

const AuthContext = React.createContext<AuthContextValue | undefined>(undefined);

interface AuthProviderProps {
  children: React.ReactNode;
}

export function AuthProvider({ children }: AuthProviderProps) {
  const [tokens, setTokens] = React.useState<AuthTokens | null>(null);
  const [user, setUser] = React.useState<UserSummary | null>(null);
  const [isLoading, setIsLoading] = React.useState<boolean>(true);

  React.useEffect(() => {
    if (typeof window === "undefined") {
      return;
    }

    try {
      const stored = window.localStorage.getItem(STORAGE_KEY);
      if (stored) {
        const parsed = JSON.parse(stored) as PersistedAuthState;
        setTokens(parsed.tokens);
        setUser(parsed.user);
      }
    } catch (error) {
      console.warn("Failed to parse stored auth state", error);
      window.localStorage.removeItem(STORAGE_KEY);
    } finally {
      setIsLoading(false);
    }
  }, []);

  React.useEffect(() => {
    if (typeof window === "undefined") {
      return;
    }

    const clearCookies = () => {
      document.cookie = `${COOKIE_ACCESS_TOKEN}=; path=/; max-age=0; sameSite=lax`;
      document.cookie = `${COOKIE_REFRESH_TOKEN}=; path=/; max-age=0; sameSite=lax`;
    };

    if (!tokens) {
      clearCookies();
      window.localStorage.removeItem(STORAGE_KEY);
      return;
    }

    const payload: PersistedAuthState = {
      tokens,
      user,
    };

    window.localStorage.setItem(STORAGE_KEY, JSON.stringify(payload));

    const cookieAttributes = `path=/; max-age=${COOKIE_MAX_AGE}; sameSite=lax`;
    document.cookie = `${COOKIE_ACCESS_TOKEN}=${encodeURIComponent(tokens.accessToken)}; ${cookieAttributes}`;
    document.cookie = `${COOKIE_REFRESH_TOKEN}=${encodeURIComponent(tokens.refreshToken)}; ${cookieAttributes}`;

    return () => {
      clearCookies();
    };
  }, [tokens, user]);

  const signIn = React.useCallback((payload: PersistedAuthState) => {
    setTokens(payload.tokens);
    setUser(payload.user);
  }, []);

  const signOut = React.useCallback(() => {
    setTokens(null);
    setUser(null);
  }, []);

  const updateUser = React.useCallback((next: UserSummary | null) => {
    setUser(next);
  }, []);

  const refresh = React.useCallback(async () => {
    if (!tokens?.refreshToken) {
      signOut();
      return null;
    }

    try {
      const nextTokens = await refreshTokens(tokens.refreshToken);
      setTokens(nextTokens);
      return nextTokens;
    } catch (error) {
      console.warn("Refresh token failed", error);
      signOut();
      return null;
    }
  }, [tokens?.refreshToken, signOut]);

  const value = React.useMemo<AuthContextValue>(
    () => ({
      user,
      tokens,
      isAuthenticated: Boolean(tokens && user),
      isLoading,
      signIn,
      signOut,
      updateUser,
      refresh,
    }),
    [user, tokens, isLoading, signIn, signOut, updateUser, refresh],
  );

  return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}

export function useAuth() {
  const context = React.useContext(AuthContext);
  if (!context) {
    throw new Error("useAuth must be used within an AuthProvider");
  }

  return context;
}
